package com.quiz.bis.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.DeleteJoinWrapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.quiz.bis.domain.bo.ExamSubgroupAddBo;
import com.quiz.bis.domain.bo.ExamSubgroupMemberBo;
import com.quiz.bis.domain.bo.ExamSubgroupUpdateBo;
import com.quiz.bis.domain.model.ExamGroupMember;
import com.quiz.bis.domain.model.ExamSubgroup;
import com.quiz.bis.domain.model.ExamSubgroupMember;
import com.quiz.bis.domain.vo.ExamSubgroupMemberVo;
import com.quiz.bis.domain.vo.ExamSubgroupVo;
import com.quiz.bis.mapper.ExamSubgroupMapper;
import com.quiz.bis.mapper.ExamGroupMemberMapper;
import com.quiz.bis.mapper.ExamSubgroupMemberMapper;
import com.quiz.bis.service.IExamSubgroupService;
import com.quiz.common.core.domain.R;
import com.quiz.common.core.domain.entity.SysUser;
import com.quiz.common.exception.ServiceException;
import com.quiz.common.mybatis.core.page.PageQuery;
import com.quiz.common.mybatis.core.page.TableDataInfo;
import com.quiz.common.mybatis.core.query.MPJLambdaWrapperPlus;
import com.quiz.common.mybatis.core.query.PlusWrappers;
import com.quiz.common.utils.SecurityUtils;
import com.quiz.common.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 分组服务实现
 */
@Service
@RequiredArgsConstructor
public class ExamSubgroupServiceImpl implements IExamSubgroupService {
    private final ExamSubgroupMapper subgroupMapper;
    private final ExamSubgroupMemberMapper subgroupMemberMapper;
    private final ExamGroupMemberMapper groupMemberMapper;

    @Override
    public TableDataInfo<?> listSubgroups(Long groupId) {
        // 验证用户是否有权限访问该考试组
        checkGroupAccess(groupId);

        List<ExamSubgroup> subgroups = subgroupMapper.selectByGroupId(groupId);

        // 构建树形结构
        List<ExamSubgroupVo> tree = buildSubgroupTree(subgroups);

        // 统计每个分组的成员数量
        Map<String, Integer> memberCountMap = new HashMap<>();
        for (ExamSubgroup subgroup : subgroups) {
            int count = subgroupMapper.countMembers(subgroup.getId());
            memberCountMap.put(subgroup.getId().toString(), count);
        }

        // 设置成员数量
        setMemberCount(tree, memberCountMap);

        return TableDataInfo.build(tree);
    }

    @Override
    @Transactional
    public R<Long> addSubgroup(ExamSubgroupAddBo bo) {
        // 验证用户是否有权限操作该考试组
        checkGroupAccess(bo.getExamGroupId());

        // 验证父分组是否存在
        if (bo.getParentId() != null) {
            ExamSubgroup parent = subgroupMapper.selectById(bo.getParentId());
            if (parent == null || !parent.getExamGroupId().equals(bo.getExamGroupId())) {
                throw new ServiceException("父分组不存在或不属于当前考试组");
            }
        }

        ExamSubgroup subgroup = new ExamSubgroup();
        subgroup.setExamGroupId(bo.getExamGroupId());
        subgroup.setParentId(bo.getParentId());
        subgroup.setName(bo.getName());
        subgroup.setSort(bo.getSort());
        subgroup.setCreateBy(SecurityUtils.getUserId().toString());

        subgroupMapper.insert(subgroup);

        // 更新层级路径
        updateLevelPath(subgroup);

        return R.ok(subgroup.getId());
    }

    @Override
    @Transactional
    public R<Void> updateSubgroup(ExamSubgroupUpdateBo bo) {
        ExamSubgroup subgroup = subgroupMapper.selectById(bo.getId());
        if (subgroup == null) {
            throw new ServiceException("分组不存在");
        }

        // 验证用户是否有权限操作该考试组
        checkGroupAccess(subgroup.getExamGroupId());

        subgroup.setName(bo.getName());
        subgroup.setUpdateBy(SecurityUtils.getUserId().toString());
        subgroupMapper.updateById(subgroup);

        return R.ok();
    }

    @Override
    @Transactional
    public R<Void> deleteSubgroups(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return R.fail("请选择要删除的分组");
        }

        // 验证所有分组是否属于同一个考试组
        List<ExamSubgroup> subgroups = subgroupMapper.selectBatchIds(ids);
        if (subgroups.isEmpty()) {
            return R.fail("分组不存在");
        }

        Long groupId = subgroups.get(0).getExamGroupId();
        for (ExamSubgroup subgroup : subgroups) {
            if (!subgroup.getExamGroupId().equals(groupId)) {
                throw new ServiceException("不能同时删除不同考试组的分组");
            }
        }

        // 验证用户是否有权限操作该考试组
        checkGroupAccess(groupId);

        // 检查是否有子分组
        List<ExamSubgroup> children = subgroupMapper.selectList(
                new LambdaQueryWrapper<ExamSubgroup>()
                        .in(ExamSubgroup::getParentId, ids)
                        .eq(ExamSubgroup::getDelFlag, 0)
        );
        if (!children.isEmpty()) {
            throw new ServiceException("请先删除子分组");
        }

        // 检查分组下是否有成员
        List<ExamSubgroupMember> members = subgroupMemberMapper.selectList(
                new LambdaQueryWrapper<ExamSubgroupMember>()
                        .in(ExamSubgroupMember::getSubgroupId, ids)
                        .eq(ExamSubgroupMember::getDelFlag, 0)
        );
        if (!members.isEmpty()) {
            throw new ServiceException("请先移除分组下的成员");
        }

        // 逻辑删除分组
        subgroupMapper.deleteBatchIds(ids);

        return R.ok();
    }

    @Override
    public TableDataInfo<?> listSubgroupMembers(Long subgroupId, PageQuery pageQuery, String searchKey) {
        ExamSubgroup subgroup = subgroupMapper.selectById(subgroupId);
        if (subgroup == null) {
            throw new ServiceException("分组不存在");
        }

        // 验证用户是否有权限操作该考试组
        checkGroupAccess(subgroup.getExamGroupId());

        // 构建查询条件
        LambdaQueryWrapper<ExamSubgroupMember> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ExamSubgroupMember::getSubgroupId, subgroupId)
                .eq(ExamSubgroupMember::getDelFlag, 0);

        // 分页查询成员ID
        Page<ExamSubgroupMember> page = subgroupMemberMapper.selectPage(pageQuery.build(), wrapper);
        List<Long> memberIds = page.getRecords().stream()
                .map(ExamSubgroupMember::getUserId)
                .collect(Collectors.toList());

        if (memberIds.isEmpty()) {
            return TableDataInfo.build(new ArrayList<>());
        }

        // 查询成员详细信息
        MPJLambdaWrapperPlus<ExamGroupMember> memberWrapper = new MPJLambdaWrapperPlus<>();
        memberWrapper.in(ExamGroupMember::getUserId, memberIds)
                .selectAll(ExamGroupMember.class)
                .select(SysUser::getUserName)
                .leftJoin(SysUser.class, SysUser::getUserId, ExamGroupMember::getUserId)
                .eq(ExamGroupMember::getExamGroupId, subgroup.getExamGroupId())
                .eq(ExamGroupMember::getDelFlag, 0);

        if (StringUtils.isNotBlank(searchKey)) {
            memberWrapper.and(w -> w.like(ExamGroupMember::getUserId, searchKey)
                    .or()
                    .like(ExamGroupMember::getUserId, searchKey));
        }

        List<ExamSubgroupMemberVo> members = groupMemberMapper.selectList(memberWrapper)
                .stream()
                .map(m -> {
                    ExamSubgroupMemberVo vo = new ExamSubgroupMemberVo();
                    vo.setUserId(m.getUserId());
                    vo.setUserName(m.getUserName());
                    vo.setAvatar(null);
                    vo.setRole(m.getRole());
                    vo.setJoinTime(m.getCreateTime());
                    return vo;
                })
                .collect(Collectors.toList());

        return TableDataInfo.build(members, page.getTotal());
    }

    @Override
    @Transactional
    public R<Void> addSubgroupMembers(ExamSubgroupMemberBo bo) {
        ExamSubgroup subgroup = subgroupMapper.selectById(bo.getSubgroupId());
        if (subgroup == null) {
            throw new ServiceException("分组不存在");
        }

        // 验证用户是否有权限操作该考试组
        checkGroupAccess(subgroup.getExamGroupId());

        if (bo.getUserIds() == null || bo.getUserIds().isEmpty()) {
            return R.fail("请选择要添加的成员");
        }

        // 验证成员是否都是考生
        List<Long> invalidMembers = groupMemberMapper.selectNonStudentMembers(
                subgroup.getExamGroupId(), bo.getUserIds());
        if (!invalidMembers.isEmpty()) {
            throw new ServiceException("只能添加考生角色成员到分组");
        }

        // 过滤已存在的成员
        List<ExamSubgroupMember> existingMembers = subgroupMemberMapper.selectList(
                new LambdaQueryWrapper<ExamSubgroupMember>()
                        .eq(ExamSubgroupMember::getSubgroupId, bo.getSubgroupId())
                        .in(ExamSubgroupMember::getUserId, bo.getUserIds())
                        .eq(ExamSubgroupMember::getDelFlag, 0)
        );

        Set<Long> existingUserIds = existingMembers.stream()
                .map(ExamSubgroupMember::getUserId)
                .collect(Collectors.toSet());

        List<ExamSubgroupMember> toAdd = bo.getUserIds().stream()
                .filter(userId -> !existingUserIds.contains(userId))
                .map(userId -> {
                    ExamSubgroupMember member = new ExamSubgroupMember();
                    member.setSubgroupId(bo.getSubgroupId());
                    member.setUserId(userId);
                    member.setCreateBy(SecurityUtils.getUserId().toString());
                    return member;
                })
                .collect(Collectors.toList());

        if (!toAdd.isEmpty()) {
            subgroupMemberMapper.insertBatch(toAdd);
        }

        return R.ok();
    }

    @Override
    @Transactional
    public R<Void> removeSubgroupMembers(ExamSubgroupMemberBo bo) {
        ExamSubgroup subgroup = subgroupMapper.selectById(bo.getSubgroupId());
        if (subgroup == null) {
            throw new ServiceException("分组不存在");
        }

        // 验证用户是否有权限操作该考试组
        checkGroupAccess(subgroup.getExamGroupId());

        if (bo.getUserIds() == null || bo.getUserIds().isEmpty()) {
            return R.fail("请选择要移除的成员");
        }


        // 逻辑删除成员关联
        subgroupMemberMapper.deleteMembers(bo.getSubgroupId(), CollUtil.join(bo.getUserIds(), ","));

        return R.ok();
    }

    // ========== 私有方法 ==========

    private void checkGroupAccess(Long groupId) {
        Long userId = SecurityUtils.getUserId();
        boolean hasAccess = groupMemberMapper.exists(
                Wrappers.lambdaQuery(ExamGroupMember.class)
                        .eq(ExamGroupMember::getExamGroupId, groupId)
                        .eq(ExamGroupMember::getUserId, userId)
                        .eq(ExamGroupMember::getDelFlag, 0)
        );
        if (!hasAccess) {
            throw new ServiceException("您没有权限操作该考试组");
        }
    }

    private List<ExamSubgroupVo> buildSubgroupTree(List<ExamSubgroup> subgroups) {
        List<ExamSubgroupVo> tree = new ArrayList<>();
        Map<Long, ExamSubgroupVo> map = new HashMap<>();

        // 先创建所有节点的映射
        for (ExamSubgroup subgroup : subgroups) {
            ExamSubgroupVo vo = new ExamSubgroupVo();
            vo.setId(subgroup.getId().toString());
            vo.setExamGroupId(subgroup.getExamGroupId());
            vo.setParentId(subgroup.getParentId());
            vo.setName(subgroup.getName());
            vo.setCreateTime(subgroup.getCreateTime());
            vo.setChildren(new ArrayList<>());
            vo.setSort(subgroup.getSort());
            map.put(subgroup.getId(), vo);
        }

        // 构建树形结构
        for (ExamSubgroupVo vo : map.values()) {
            if (vo.getParentId() == null || vo.getParentId() == 0) {
                tree.add(vo);
            } else {
                ExamSubgroupVo parent = map.get(vo.getParentId());
                if (parent != null) {
                    parent.getChildren().add(vo);
                }
            }
        }

        // 按sort排序
        sortTree(tree);

        return tree;
    }

    private void sortTree(List<ExamSubgroupVo> tree) {
        tree.sort(Comparator.comparingInt(ExamSubgroupVo::getSort));
        for (ExamSubgroupVo vo : tree) {
            if (vo.getChildren() != null && !vo.getChildren().isEmpty()) {
                sortTree(vo.getChildren());
            }
        }
    }

    private void setMemberCount(List<ExamSubgroupVo> tree, Map<String, Integer> memberCountMap) {
        for (ExamSubgroupVo vo : tree) {
            vo.setMemberCount(memberCountMap.getOrDefault(vo.getId(), 0));
            if (vo.getChildren() != null && !vo.getChildren().isEmpty()) {
                setMemberCount(vo.getChildren(), memberCountMap);
            }
        }
    }

    private void updateLevelPath(ExamSubgroup subgroup) {
        StringBuilder levelPath = new StringBuilder();
        if (subgroup.getParentId() != null) {
            ExamSubgroup parent = subgroupMapper.selectById(subgroup.getParentId());
            if (parent != null) {
                levelPath.append(parent.getLevelPath());
            }
        }
        levelPath.append(subgroup.getId()).append(",");
        subgroup.setLevelPath(levelPath.toString());
        subgroupMapper.updateById(subgroup);
    }
}